/**
 * 
 */
package ro.dta.idbi.patterns;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ro.dta.idbi.interfaces.IntegrationOperation;
import ro.dta.idbi.model.AbstractPattern;
import ro.dta.idbi.model.Utils;
import uk.ac.ic.doc.automed.IntegrityException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.SchemaObject;

/**
 * <b>Redundant foreign-key removal</b><br />
 * 
 * Example of use:<br />
 * <code>redundant_fk_removal (&lt;&lt;fk_name2,t1,&lt;&lt;t1,c1&gt;&gt;, ..., &lt;&lt;t1,cn&gt;&gt;,t2,&lt;&lt;t2,c1&gt;&gt;,..., &lt;&lt;t2,cn&gt;&gt;&gt;&gt;, &lt;&lt;fk_name1,p1,&lt;&lt;p1,c1&gt;&gt;, ..., &lt;&lt;p1,cn&gt;&gt;,p2,&lt;&lt;p2,c1&gt;&gt;,..., &lt;&lt;p2,cn&gt;&gt;&gt;&gt;)</code>
 * <br />
 * 
 * The redundant column <i>col</i> in the <i>child_table</i> is removed
 * 
 * @author Tudor Dobrila
 * 
 */
public class RedundantFK extends AbstractPattern {

	/**
	 * Name of the pattern
	 */
	public static final String NAME = "Redundant foreign key removal";

	/**
	 * Description of the pattern
	 */
	public static final String DESCRIPTION = "Remove the redundant foreign key";

	/**
	 * Name of the command associated with the pattern
	 */
	public static final String COMMAND = "redundant_fk_removal";

	/**
	 * Integration phase during which the command is applied
	 */
	public static final EnumSet<IntegrationOperation> OPERATION = EnumSet
			.of(IntegrationOperation.IMPROVEMENT);

	/**
	 * Definition of the foreign key
	 */
	private String fkDefinition;

	/**
	 * List of columns belonging to the source table of the FK
	 */
	private List<String> sourceCols;

	/**
	 * Name of the source table
	 */
	private String sourceTable;

	/**
	 * Parent table of the source table
	 */
	private String parentTable;

	/**
	 * List of columns belonging to the target table
	 */
	private List<String> targetCols;

	/**
	 * Redundant foreign key removal pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Source schema over which the transformation is applied
	 */
	public RedundantFK(final Schema sourceSchema) throws NotFoundException, IntegrityException {
		super(sourceSchema);

		String fkDef = "<<(" + NAME_REGEX + ")" + COMMA_REGEX + TABLE_AND_COLS_REGEX + COMMA_REGEX
				+ TABLE_AND_COLS_REGEX + ">>";
		pattern = Pattern.compile("^" + COMMAND + "[ ]*\\((" + fkDef + ")" + COMMA_REGEX + "("
				+ fkDef + ")\\)$");
	}

	/**
	 * Redundant foreign key removal pattern class constructor
	 * 
	 * @param sourceSchema
	 *            Name of source schema over which the transformation is applied
	 */
	public RedundantFK(final String sourceSchema) throws NotFoundException, IntegrityException {
		this(Schema.getSchema(sourceSchema));
	}

	@Override
	protected void parse(String trans) {
		final Matcher matcher = pattern.matcher(trans);
		matcher.find();

		fkDefinition = matcher.group(1);
		sourceTable = matcher.group(3);
		sourceCols = getColumns(matcher.group(4));
		targetCols = getColumns(matcher.group(9));
		parentTable = matcher.group(15);
	}

	@Override
	protected List<String> getPrimitiveCommands() throws NotFoundException, IntegrityException {
		List<String> result = new ArrayList<String>();
		StringBuilder cmd = new StringBuilder();

		// Step 1: remove the foreign key constraint
		cmd.append("delete (foreignkey:");
		cmd.append(fkDefinition);
		cmd.append(")");
		result.add(cmd.toString());

		// Step 2: remove the columns in the source table belonging to the FK
		for (int i = 0; i < sourceCols.size(); i++) {
			String s = sourceCols.get(i);
			String t = targetCols.get(i);
			SchemaObject crtCol = sourceSchema.getSchemaObject(s);
			Object[] crtColDef = crtCol.getSchemeDefinition();
			StringBuilder extent = new StringBuilder("[ ");
			extent.append("{x,y} | {x} <- <<").append(sourceTable).append(">>; ");
			extent.append("{x,y} <- <<").append(parentTable).append(",").append(crtColDef[1]).append(">>; ");
			extent.append("{z,y} <- ").append(t);
			extent.append(" ]");

			cmd.setLength(0);
			cmd.append("delete (");
			cmd.append(Utils.genColRepresentation(sourceTable, crtColDef[1], crtColDef[2],
					crtColDef[3]));
			cmd.append(", ").append(extent).append(")");
			result.add(cmd.toString());
		}

		return result;
	}

	@Override
	protected boolean verify() {
		// TODO Auto-generated method stub
		return true;
	}

}
